package com.peas.platform.common.core.utils;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import cn.hutool.poi.excel.StyleSet;
import com.peas.platform.common.core.annotation.Comment;
import com.peas.platform.common.core.constant.Constants;
import com.peas.platform.common.core.dto.BaseDto;
import com.peas.platform.common.core.enums.BaseEnum;
import com.peas.platform.common.core.vo.BaseVo;
import io.swagger.annotations.ApiModelProperty;
import lombok.SneakyThrows;
import org.apache.poi.ss.usermodel.*;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

public class ExcelTool {

    public static <V extends BaseVo> List<String> extractHead(Class<V> clazz) {
        List<String> head = new ArrayList<>();
        head.add("ID");
        for (Field f : clazz.getDeclaredFields()) {
            f.setAccessible(true);
            ApiModelProperty amp = f.getAnnotation(ApiModelProperty.class);
            if (amp != null) {
                head.add(amp.value());
            }
        }
        head.add("创建时间");
        head.add("最后修改时间");
        return head;
    }

    @SneakyThrows
    public static <D extends BaseDto, V extends BaseVo> List<List<?>> extractData(List<D> list, Class<V> clazz) {
        List<List<?>> data = new ArrayList<>();
        for (D dto : list) {
            V vo = BeanUtil.copyProperties(dto, clazz);
            List<Serializable> row = new ArrayList<>();
            row.add(String.valueOf(dto.getId()));
            for (Field f : clazz.getDeclaredFields()) {
                f.setAccessible(true);
                ApiModelProperty amp = f.getAnnotation(ApiModelProperty.class);
                if (amp != null) {
                    row.add(ExcelTool.convertValue(f.get(vo)));
                }
            }
            row.add(DateUtil.formatDateTime(dto.getCreateTime()));
            row.add(DateUtil.formatDateTime(dto.getUpdateTime()));
            data.add(row);
        }
        return data;
    }

    public static ExcelWriter genExcelWriter(List<String> sheetNames, List<List<String>> heads, List<List<List<?>>> datas) {
        Assert.notNull(sheetNames, "参数错误");
        Assert.notNull(heads, "参数错误");
        Assert.isTrue(sheetNames.size() == heads.size(), "参数错误");
        ExcelWriter writer = ExcelUtil.getWriter(true);
        for (int i = 0; i < sheetNames.size(); i++) {
            writer.setSheet(i).renameSheet(sheetNames.get(i));
            StyleSet style = writer.getStyleSet();
            CellStyle headStyle = style.getHeadCellStyle();
            ExcelTool.setHeadStyle(headStyle, writer);
            CellStyle dataStyle = style.getCellStyle();
            ExcelTool.setDataStyle(dataStyle, writer);
            writer.writeHeadRow(heads.get(i));
            if (CollUtil.isEmpty(datas) && datas.size() >= i + 1)
                writer.write(datas.get(i));
        }
        return writer;
    }

    public static ExcelWriter genExcelWriter(List<String> head, List<List<?>> data) {
        ExcelWriter writer = ExcelUtil.getWriter(true);
        StyleSet style = writer.getStyleSet();
        CellStyle headStyle = style.getHeadCellStyle();
        ExcelTool.setHeadStyle(headStyle, writer);
        CellStyle dataStyle = style.getCellStyle();
        ExcelTool.setDataStyle(dataStyle, writer);
        writer.writeHeadRow(head);
        writer.write(data);
        return writer;
    }

    public static String convertValue(Object o, Comment comment) {
        final String v = convertValue(o);
        if (StrUtil.isNotBlank(comment.enumType())) {
            Class<? extends BaseEnum> enumClass = Constants.enums.get(comment.enumType());
            if (enumClass != null) {
                Map<String, String> map = BaseEnum.getMapList(enumClass).stream().filter(m -> StrUtil.equals(v, m.get("key"))).findFirst().orElse(null);
                return CollUtil.isEmpty(map) ? v : map.get("key") + "-" + map.get("value");
            }
        }
        if (StrUtil.isNotBlank(comment.dictType())) {
            return v;
        }
        if (StrUtil.isNotBlank(comment.foreignType())) {
            return v;
        }
        return v;
    }

    public static String convertValue(Object o, ApiModelProperty amp) {
        final String v = convertValue(o);
        if (StrUtil.startWith(amp.notes(), Constants.VALUE_PREFIX_ENUM)) {
            Class<? extends BaseEnum> enumClass = Constants.enums.get(amp.notes().substring(Constants.VALUE_PREFIX_ENUM.length()));
            if (enumClass != null) {
                Map<String, String> map = BaseEnum.getMapList(enumClass).stream().filter(m -> StrUtil.equals(v, m.get("key"))).findFirst().orElse(null);
                return CollUtil.isEmpty(map) ? v : map.get("key") + "-" + map.get("value");
            }
        }
        if (StrUtil.startWith(amp.notes(), Constants.VALUE_PREFIX_DICT)) {
            return v;
        }
        if (StrUtil.startWith(amp.notes(), Constants.VALUE_PREFIX_FOREIGN)) {
            return v;
        }
        return v;
    }

    public static String convertValue(Object o) {
        if (o == null) {
            return StrUtil.EMPTY;
        }
        if (o instanceof String) {
            return (String) o;
        }
        if (o instanceof BigDecimal) {
            BigDecimal v = (BigDecimal) o;
            return v.toPlainString();
        }
        if (o instanceof Number) {
            return String.valueOf(o);
        }
        if (o instanceof Date) {
            Date v = (Date) o;
            return DateUtil.formatDateTime(v);
        }
        return String.valueOf(o);
    }

    public static void setHeadStyle(CellStyle headStyle, ExcelWriter writer) {
        Font headFont = writer.createFont();
        headFont.setBold(true);
        headStyle.setFont(headFont);
        headStyle.setBorderTop(BorderStyle.THIN);
        headStyle.setBorderLeft(BorderStyle.THIN);
        headStyle.setBorderRight(BorderStyle.THIN);
        headStyle.setBorderBottom(BorderStyle.THIN);
        headStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
        headStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
    }

    public static void setDataStyle(CellStyle dataStyle, ExcelWriter writer) {
        Font dataFont = writer.createFont();
        dataFont.setBold(false);
        dataStyle.setFont(dataFont);
        dataStyle.setBorderTop(BorderStyle.NONE);
        dataStyle.setBorderLeft(BorderStyle.THIN);
        dataStyle.setBorderRight(BorderStyle.THIN);
        dataStyle.setBorderBottom(BorderStyle.THIN);
    }

    public static CellStyle createHeadStyle(Workbook book) {
        Font headFont = book.createFont();
        headFont.setBold(true);
        CellStyle headStyle = book.createCellStyle();
        headStyle.setFont(headFont);
        headStyle.setBorderTop(BorderStyle.THIN);
        headStyle.setBorderLeft(BorderStyle.THIN);
        headStyle.setBorderRight(BorderStyle.THIN);
        headStyle.setBorderBottom(BorderStyle.THIN);
        headStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
        headStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        return headStyle;
    }

    public static CellStyle createDataStyle(Workbook book) {
        Font dataFont = book.createFont();
        dataFont.setBold(false);
        CellStyle dataStyle = book.createCellStyle();
        dataStyle.setFont(dataFont);
        dataStyle.setDataFormat(book.createDataFormat().getFormat("@"));
        dataStyle.setBorderTop(BorderStyle.NONE);
        dataStyle.setBorderLeft(BorderStyle.THIN);
        dataStyle.setBorderRight(BorderStyle.THIN);
        dataStyle.setBorderBottom(BorderStyle.THIN);
        return dataStyle;
    }

    public static CellStyle createSuccessStyle(Workbook book) {
        Font successFont = book.createFont();
        successFont.setColor((short) 0x70f0);
        CellStyle successStyle = book.createCellStyle();
        successStyle.setFont(successFont);
        return successStyle;
    }

    public static CellStyle createErrorStyle(Workbook book) {
        Font errFont = book.createFont();
        errFont.setColor(Font.COLOR_RED);
        CellStyle errStyle = book.createCellStyle();
        errStyle.setFont(errFont);
        return errStyle;
    }

}
